#include "canalysis_hash.h"
#define VAR_NAME_TO_STR(var) #var


static uint32_t hash(const void* key, int len, uint32_t seed);

// 创建一个固定容量的哈希表
HashMap* hashmap_create() {
	HashMap* map = (HashMap*)calloc(HASHMAP_CAPACITY, sizeof(HashMap));
    if (map == NULL) {
        printf("哈希表创建失败！\n");
        //exit(1);
        return NULL;
    }
	map->length = HASHMAP_CAPACITY;
	map->hash_seed = time(NULL);

    printf("哈希表创建成功！\n");
    return map;
}


// 销毁一个哈希表
void hashmap_destroy(HashMap* map) {
    //map->length = 0;
    map->hash_seed = 0;
    for (int i = 0; i < map->length; i++) {
        while (map->buckets[i]!=NULL) {
            KeyValueNode* temp = map->buckets[i];
            map->buckets[i] = map->buckets[i]->next;
            free(temp);
        }
    }
    map->length = 0;
    free(map);
    map = NULL;
    printf("哈希表%s已销毁！\n", VAR_NAME_TO_STR(map));
}

// 插入一个键值对
ValueType hashmap_put(HashMap* map, KeyType key, ValueType val) {
    ValueType old_val;
    uint32_t hash_value = hash(key, strlen(key), map->hash_seed);
    int i = hash_value % map->length;

    printf("键值对开始创建!key值是%s\n",key);

    KeyValueNode* new_node = (KeyValueNode*)calloc(1, sizeof(KeyValueNode));
    if (new_node == NULL) {
        printf("节点创建失败！\n");
        return NULL;
    }
    new_node->key = key;
    new_node->val = val;
    new_node->next = NULL;
    
    KeyValueNode* temp = map->buckets[i];
    while (temp != NULL) {
        if (strcmp(temp->key,key) == 0) {
            old_val = temp->val;
            temp->val = new_node->val;
            return old_val;
        }  
        temp = temp->next;
    }
    new_node->next = map->buckets[i];
    map->buckets[i] = new_node;
    /* new_node->next = NULL; */
    printf("键值对创建成功!key值是%s\n",key);
    free(temp);
    return val;
}
// 查询一个键值对
ValueType hashmap_get(HashMap* map, KeyType key) {
    ValueType res_value;
    uint32_t hash_value = hash(key, strlen(key), map->hash_seed);
    int i = hash_value % map->length;
    KeyValueNode* temp = map->buckets[i];
    while (temp != NULL) {
        if (strcmp(temp->key,key)==0) {
            res_value = temp->val;
            printf("找到该键值对,已返回！\n");
            return res_value;
        }
        temp = temp->next;
    }
    free(temp);
    printf("未找到该键值对！\n");
    return NULL;
}
// 删除某个键值对
bool hashmap_remove(HashMap* map, KeyType key) {

    uint32_t hash_value = hash(key, strlen(key), map->hash_seed);
    int i = hash_value % map->length;

    KeyValueNode* previous = NULL;
    KeyValueNode* temp = map->buckets[i];
    while (temp != NULL) {
        if (temp->key == key) {
            if (previous == NULL) {
                map->buckets[i] = temp->next;
                free(temp);
                printf("键值对已删除！\n");
                return true;
            }
            previous->next = temp->next;
            free(temp);
            printf("键值对已删除！\n");
            return true; 
        }
        previous = temp;
        temp = temp->next;
    }
    free(temp);
    printf("未找到对应的键值对！\n");
    return false;
}

/* murmur_hash2 */
static uint32_t hash(const void* key, int len, uint32_t seed) {
    const uint32_t m = 0x5bd1e995;
    const int r = 24;
    uint32_t h = seed ^ len;
    const unsigned char* data = (const unsigned char*)key;

    while (len >= 4) {
        uint32_t k = *(uint32_t*)data;
        k *= m;
        k ^= k >> r;
        k *= m;
        h *= m;
        h ^= k;
        data += 4;
        len -= 4;
    }

    switch (len) {
    case 3: h ^= data[2] << 16;
    case 2: h ^= data[1] << 8;
    case 1: h ^= data[0];
        h *= m;
    };

    h ^= h >> 13;
    h *= m;
    h ^= h >> 15;

    return h;
}


/* int main(){ */
/*     Canalysis_t canalysis[10]; */

/*     canalysis[0].username = (char*)calloc(100,sizeof(char)); */
/*     canalysis[1].username = (char*)calloc(100,sizeof(char)); */
/*     canalysis[2].username = (char*)calloc(100,sizeof(char)); */
/*     canalysis[3].username = (char*)calloc(100,sizeof(char)); */
/*     canalysis[4].username = (char*)calloc(100,sizeof(char)); */
/*     char name1[] = "zhangsan"; */
/*     char name2[] = "lisi"; */
/*     char name3[] = "wangwu"; */
/*     char name4[] = "xiaoming"; */
/*     char name5[] = "xiaohuang"; */
/*     strcpy(canalysis[0].username,name1); */
/*     canalysis[0].flag = 1; */  
/*     strcpy(canalysis[1].username,name2); */
/*     canalysis[1].flag = 2; */  
/*     strcpy(canalysis[2].username,name3); */
/*     canalysis[2].flag = 3; */  
/*     strcpy(canalysis[3].username,name4); */
/*     canalysis[3].flag = 4; */  
/*     strcpy(canalysis[4].username,name5); */
/*     canalysis[4].flag = 5; */  

/*     printf("name is %s flag is %d\n",canalysis[0].username,canalysis[0].flag); */
/*     printf("name is %s flag is %d\n",canalysis[1].username,canalysis[1].flag); */
/*     printf("name is %s flag is %d\n",canalysis[2].username,canalysis[2].flag); */
/*     printf("name is %s flag is %d\n",canalysis[3].username,canalysis[3].flag); */
/*     printf("name is %s flag is %d\n",canalysis[4].username,canalysis[4].flag); */
/*     HashMap* map = hashmap_create(); */
/*     hashmap_put(map,canalysis[0].username,&canalysis[0]); */    
/*     hashmap_put(map,canalysis[1].username,&canalysis[1]); */    
/*     hashmap_put(map,canalysis[2].username,&canalysis[2]); */    
/*     hashmap_put(map,canalysis[3].username,&canalysis[3]); */    
/*     hashmap_put(map,canalysis[4].username,&canalysis[4]); */    

/*     Canalysis_t* temp; */

/*     temp = hashmap_get(map,"zhangsan"); */
/*     printf("name is %s flag is %d\n",temp->username,temp->flag); */

/*     temp = hashmap_get(map,"lisi"); */
/*     printf("name is %s flag is %d\n",temp->username,temp->flag); */

/*     temp = hashmap_get(map,"wangwu"); */
/*     printf("name is %s flag is %d\n",temp->username,temp->flag); */

/*     temp = hashmap_get(map,"xiaoming"); */
/*     printf("name is %s flag is %d\n",temp->username,temp->flag); */
    
/*     hashmap_remove(map,"xiaoming"); */
/*     printf("name is %s flag is %d\n",temp->username,temp->flag); */

/*     temp = hashmap_get(map,"xiaohuang"); */
/*     printf("name is %s flag is %d\n",temp->username,temp->flag); */

/* } */



